

/**
 * @file CombinedVar.hpp
 * Class to define and handle 'descriptions' of GNSS variables.
 */

#ifndef GPSTK_CombinedVar_HPP
#define GPSTK_CombinedVar_HPP

//============================================================================
//
//  2020/03/20 shjzhang
//
//============================================================================



#include "DataStructures.hpp"
#include "StochasticModel.hpp"
#include "Variable.hpp"



namespace gpstk
{

      /** @addtogroup DataStructures */
      //@{

      /// Class to define and handle 'descriptions' of GNSS variables.
   class CombinedVar
   {
   public:

         /// Default constructor for CombinedVar
      CombinedVar()
      {};


         /** Common constructor for CombinedVar.
          *  By default, it is indexed by SourceID.
          *
          * @param type             TypeID of variable.
          * @param pModel           Pointer to StochasticModel associated with
          *                         this variable. By default, it is a white
          *                         noise model.
          * @param sourceIndexed    Whether this variable is SourceID-indexed
          *                         or not. By default, it IS SourceID-indexed.
          * @param satIndexed       Whether this variable is SatID-indexed
          *                         or not. By default, it is NOT.
          * @param variance         Initial variance assigned to this variable.
          * @param coef             Default coefficient assigned.
          * @param forceCoef        Always use default coefficient.
          */
      CombinedVar( const TypeID& type1,
                   const TypeID& type2,
                   double coeff1,
                   double coeff2)
      {
          firstType = type1;
          secondType = type2;

          firstCoeff = coeff1;
          secondCoeff = coeff2;
      };


      CombinedVar& setFirstType(TypeID type)
      { 
          firstType = type; 
          return (*this); 
      };

         /// Get variable type
      TypeID getFirstType() const
      { 
          return firstType ; 
      };


      CombinedVar& setSecondType(TypeID type)
      { 
          secondType = type; 
          return (*this); 
      };


      TypeID getSecondType() const
      { 
          return secondType ; 
      };

      CombinedVar& setFirstCoeff(double coeff)
      { 
          firstCoeff = coeff; 
          return (*this); 
      };

      double getFirstCoeff() const
      { 
          return firstCoeff ; 
      };

      CombinedVar& setSecondCoeff(double coeff)
      { 
          secondCoeff = coeff; 
          return (*this); 
      };

      double getSecondCoeff() const
      { 
          return secondCoeff ; 
      };

      CombinedVar& setFirstVar(Variable var)
      { 
          firstVar = var; 
          return (*this); 
      };

      Variable getFirstVar() const
      { 
          return firstVar; 
      };

      CombinedVar& setSecondVar(Variable var)
      { 
          secondVar = var; 
          return (*this); 
      };

      Variable getSecondVar() const
      { 
          return secondVar; 
      };

         /** Set variable type
          *
          * @param type        New TypeID of variable.
          */
      CombinedVar& setFirstTypeCoeff(const TypeID& type,
                                     const double& coeff)
      { 
          firstType = type; 
          firstCoeff = coeff;
          return (*this); 
      };

         /** Set variable type
          * @param type        New TypeID of variable.
          */
      CombinedVar& setSecondTypeCoeff( const TypeID& type,
                                       const double& coeff)
      { 
          secondType = type; 
          secondCoeff = coeff;
          return (*this); 
      };


      void dump(std::ostream& s) const
      {
          s << "firstType:" << firstType 
            << "secondType:" << secondType 
            << "firstCoeff:" << firstCoeff
            << "secondCoeff:" << secondCoeff
            << "firstVar:" << firstVar
            << "secondVar:" << secondVar
            ;
      }


         /// Equality operator
      virtual bool operator==(const CombinedVar& right) const;


         /// This ordering is somewhat arbitrary, but is required to be able
         /// to use a CombinedVar as an index to a std::map, or as part of a
         /// std::set.
      virtual bool operator<(const CombinedVar& right) const;


         /// Inequality operator
      bool operator!=(const CombinedVar& right) const
      { return !(operator==(right)); }


         /// Assignment operator.
      virtual CombinedVar& operator=(const CombinedVar& right);


         /// Destructor
      virtual ~CombinedVar() {};


   private:


         /// Type of the variable
      TypeID firstType;
      TypeID secondType;

      double firstCoeff;
      double secondCoeff;

      Variable firstVar;
      Variable secondVar;


   }; // End of class 'CombinedVar'

   typedef std::set<CombinedVar> CombinedVarSet;
   typedef std::map<CombinedVar, double> CombinedVarDataMap;
   typedef std::map<CombinedVar, CombinedVarDataMap> CombinedVarCovMap;

   /// stream output for CombinedVar
   inline std::ostream& operator<<(std::ostream& s, const CombinedVar& v)
   {
       v.dump(s);
       return s;
   }

   //@}

}  // End of namespace gpstk
#endif   // GPSTK_CombinedVar_HPP
